#ifndef __mytype
#define __mytype
/**
 * this is the new version of type.h
 * in this file __Vect3 and __Vect2 will be defined,
 * because they are used so often
 * also the vector do product and cross product has been
 * defined here.
 * its product with scalar also in this file
 * mod func are also here
 * ***/
#include <iostream>
#include <cmath>
using namespace std;

/// 三维矢量
template <class _Ty>
class __Vect3{
    public:
        _Ty member[3] = {};
        /***
        __Vect3(_Ty& o1, _Ty& o2, _Ty& o3){
            member[0] = o1;
            member[1] = o2;
            member[2] = o3;
        }
        ***/
        __Vect3<_Ty>(_Ty o1, _Ty o2, _Ty o3){
            member[0] = o1;
            member[1] = o2;
            member[2] = o3;
        }
        __Vect3<_Ty>(){}
        __Vect3<_Ty>(const __Vect3<_Ty>& other){
            this->member[0] = other.member[0];
            this->member[1] = other.member[1];
            this->member[2] = other.member[2];
        }
        ~__Vect3<_Ty>(){
            //delete member;
        }
        // 重载运算符规则：
        // 如果返回为本类型：可以使用成员函数重载，且该对象必须是地一个
        // 如果运算符第一个不是该类对象，必须使用友元函数
        __Vect3<_Ty> operator=(const __Vect3<_Ty>& other){
            this->member[0] = other.member[0];
            this->member[1] = other.member[1];
            this->member[2] = other.member[2];
            return *this;
        }

        __Vect3<_Ty> operator+(const __Vect3<_Ty> & other){
            return __Vect3<_Ty>(this->member[0] + other.member[0], \
                    this->member[1] + other.member[1], \
                    this->member[2] + other.member[2]);
        }
        friend __Vect3<_Ty> operator-(const __Vect3<_Ty>& other1, const __Vect3<_Ty>& other2){
            return __Vect3(other1.member[0] - other2.member[0], \
                    other1.member[1] - other2.member[1], \
                    other1.member[2] - other2.member[2]);
        }
        friend _Ty operator*(const __Vect3<_Ty>& other1, const __Vect3<_Ty>& other2){
            return other1.member[0] * other2.member[0] + \
                other1.member[1] * other2.member[1] + \
                other1.member[2] * other2.member[2];
        }
        friend __Vect3<_Ty> Cross(const __Vect3<_Ty>& other1, const __Vect3<_Ty>& other2){
            return __Vect3<_Ty>(other1.member[1] * other2.member[2] - other1.member[2] * other2.member[1],\
                   - other1.member[0] * other2.member[2] + other1.member[2] * other2.member[0], \
                   other1.member[0] * other2.member[1] - other1.member[1] * other2.member[0]
                   );
        }
        friend ostream& operator<<(ostream& out, const __Vect3& other){
            out<<other.member[0]<<"\t"<<other.member[1]<<"\t"<<other.member[2];
            return out;
        }
        friend __Vect3<_Ty> operator*(const _Ty parameter, const __Vect3<_Ty>& me){
            return __Vect3<_Ty>(me.member[0] * parameter, \
                      me.member[1] * parameter, \
                      me.member[2] * parameter);
        }
        friend __Vect3<_Ty> operator*(const __Vect3<_Ty>& me, const _Ty parameter){
            return __Vect3<_Ty>(me.member[0] * parameter, \
                      me.member[1] * parameter, \
                      me.member[2] * parameter);
        }
        friend __Vect3<_Ty> operator/(const __Vect3<_Ty>& me, const _Ty parameter){
            return __Vect3<_Ty>(me.member[0] / parameter, \
                      me.member[1] / parameter, \
                      me.member[2] / parameter);
        }
        friend bool operator >=(const __Vect3<_Ty>&me, const __Vect3<_Ty>& other)
        {
            if (me > other || me == other)
            {
                return true;
            }
            else{
                return false;
            }
        }
        
        friend _Ty Mod(const __Vect3<_Ty>& me){
            return sqrt(me * me);
        }
        
        friend bool operator ==(const __Vect3<_Ty>& me, const __Vect3<_Ty>& other)
        {
            if((me.member[0] == other.member[0]) && \
                    (me.member[1] == other.member[1]) && \
                    (me.member[2] == other.member[2]))
            {
                return true;
            }
            else{
                return false;
            }
        }
};



/// 二维矢量
template <class _Ty>
class __Vect2{
public:
    _Ty member[2] = {};
    __Vect2<_Ty>(_Ty o1, _Ty o2){
        member[0] = o1;
        member[1] = o2;
    }
    __Vect2(){}
    ~__Vect2(){}

    __Vect2<_Ty>(const __Vect2<_Ty>& other){
        member[0] = other.member[0];
        member[1] = other.member[1];
    }

    __Vect2<_Ty>(const __Vect3<_Ty> v3){
        member[0] = v3.member[0];
        member[1] = v3.member[1];
    }

     __Vect2<_Ty> operator=(const __Vect2<_Ty>& other){
        this->member[0] = other.member[0];
        this->member[1] = other.member[1];
        return *this;
    }
    __Vect2<_Ty> operator*(const _Ty& parameter){
        return __Vect2<_Ty>(member[0] * parameter, \
                            member[1] * parameter);
    }

    __Vect2<_Ty> operator+(const __Vect2<_Ty>& other){
        return __Vect2<_Ty>(member[0] + other.member[0], \
                            member[1] + other.member[1]);
    }
    friend ostream& operator<<(ostream& out, const __Vect2<_Ty> other){
        out<<other.member[0]<<"\t"<<other.member[1];
        return out;
    }

    __Vect2<_Ty> operator / (const _Ty& parameter){
        return __Vect2<_Ty>(member[0] / parameter, member[1] / parameter);
    }

    __Vect2<_Ty> operator / (const __Vect2<_Ty>& v2){
        return __Vect2<_Ty>(member[0] / v2.member[0], member[1] / v2.member[1]);
    }
    friend __Vect2<_Ty> operator -(const __Vect2<_Ty>& mypara, const __Vect2<_Ty>& other){
        return __Vect2<_Ty>(mypara.member[0] - other.member[0], \
                mypara.member[1] - other.member[1]);
    }
    __Vect2<_Ty> Abs(){
        return __Vect2<_Ty>(abs(this->member[0]), abs(this->member[1]));
    }

    friend bool operator <= (const __Vect2<_Ty>& me, const __Vect2<_Ty>& other){
        return (me.member[0] <= other.member[0] && me.member[1] <= other.member[1]);
    }
    friend bool operator < (const __Vect2<_Ty>& me, const __Vect2<_Ty>& other){
        return (me.member[0] < other.member[0] && me.member[1] < other.member[1]);
    }
     
 

    friend bool operator >(const __Vect2<_Ty>& me, const __Vect2<_Ty>& other){
        return (me.member[0] > other.member[0] && me.member[1] > other.member[1]);
    }
    
    friend bool operator == (const __Vect2<_Ty>& me, const __Vect2<_Ty>& other){
        if (me.member[0] == other.member[0] && me.member[1] == other.member[1]){
            return true;
        }
        else{
            return false;
        }
    }
    friend bool operator >= (const __Vect2<_Ty>& me, const __Vect2<_Ty>& other){
        if(me > other | me == other)
        {
            return true;
        }
        else{
            return false;
        }
    }

    friend _Ty Mod(const __Vect2<_Ty>& me)
    {
        return sqrt(me.member[0] * me.member[0] + me.member[1] * me.member[1]);
    }
};



/// 存储grid上的场信息结构提
struct __Fdata{
    /// grid位置
    long pos[2];
    /// 十个场量, 分别为：rho, jxyz, exyz, bxyz
    double data[10];
};


/// jxyz, rho
struct __Jdata{
    double data[4];
};

typedef std::vector<__Jdata> __Jline;

void copy_to_jdata(const __Vect3<double>& jfield, const double& rho, __Jdata& jdata)
{
    jdata.data[0] = jfield.member[0];
    jdata.data[1] = jfield.member[1];
    jdata.data[2] = jfield.member[2];
    jdata.data[3] = rho;
}




/// 场量信息结构体的数组
typedef std::vector<__Fdata> __Fline;


/// grid上的一个场信息
class __Fields{
    public:
        // 使用Yee网格，则只记录网格的左下角9个
        // 左：ebj(y), 下ebj(x), 中ebj(z)
        // 标记：用i，j标记当前的网格，也标记当前网格的左下角格点，
        // 因此网格中央相当与i+1/2, j+1/2
        /// 电场
        __Vect3<double> efield;
        /// 磁场
        __Vect3<double> bfield;
        /// 电流密度
        __Vect3<double> jfield;
        /// 位置，grid
        __Vect2<long> position;
        // 计算这里不需要rho，可以先放上
        /// rho
        double rho;
        __Fields(){}
        __Fields(__Vect3<double>& electric, __Vect3<double>& magnetic, \
                __Vect3<double>& jcurrent, double rhos, __Vect2<long>\
                position):efield(electric), bfield(magnetic), \
                          jfield(jcurrent), rho(rhos), position(position){}
        __Fields(long xgrid, long ygrid){
            position.member[0] = xgrid;
            position.member[1] = ygrid;
        }
        __Fields(const __Fields& other){
            this->efield = other.efield;
            this->bfield = other.bfield;
            this->jfield = other.jfield;
            this->rho = other.rho;
            this->position = other.position;
        }
        /// 使用10维 Fdata进行初始化，
        __Fields(__Fdata& v10){
            position.member[0] = v10.pos[0];
            position.member[1] = v10.pos[1];
            rho = v10.data[0];
            __Vect3<double> jf(v10.data[1], v10.data[2], v10.data[3]);
            jfield = jf;
            __Vect3<double> ef(v10.data[4], v10.data[5], v10.data[6]);
            efield = ef;
            __Vect3<double> bf(v10.data[7], v10.data[8], v10.data[9]);
            bfield = bf;
        }~__Fields(){}
        friend ostream& operator<<(ostream& out, const __Fields& thisfield){
            out<<thisfield.position<<"\t"<<thisfield.rho<<"\t"<<thisfield.jfield<<"\t"\
                <<thisfield.efield<<"\t"\
                <<thisfield.bfield;
            return out;
        }
        //__Fields operator = (const __Fields& other){


        __Fields operator = (__Fdata& v10);
        __Fields operator = (const __Fields& other);
        void clear();
};

void __Fields::clear()
{
    __Vect3<double> zeros(0.0, 0.0, 0.0);
    this->efield = zeros;
    this->bfield = zeros;
    this->jfield = zeros;
    this->rho = 0.0;
}

__Fields __Fields::operator=(const __Fields& other){
    this->efield = other.efield;
    this->bfield = other.bfield;
    this->jfield = other.jfield;
    this->rho = other.rho;
    this->position = other.position;
    return *this;
}
/// 可以用10个double型初始化一个fields了
__Fields __Fields::operator=(__Fdata& v10)
{
    position.member[0] = v10.pos[0];
    position.member[1] = v10.pos[1];
    rho = v10.data[0];
    __Vect3<double> jf(v10.data[1], v10.data[2], v10.data[3]);
    jfield = jf;
    __Vect3<double> ef(v10.data[4], v10.data[5], v10.data[6]);
    efield = ef;
    __Vect3<double> bf(v10.data[7], v10.data[8], v10.data[9]);
    bfield = bf;
    return *this;
}






/// 拷贝场信息到fdata
void copy_to_fdata(__Fields& myfield, __Fdata& fdata)
{
    fdata.pos[0] = myfield.position.member[0];
    fdata.pos[1] = myfield.position.member[1];
    fdata.data[0] = myfield.rho;

    fdata.data[1] = myfield.jfield.member[0];
    fdata.data[2] = myfield.jfield.member[1];
    fdata.data[3] = myfield.jfield.member[2];
    
    fdata.data[4] = myfield.efield.member[0];
    fdata.data[5] = myfield.efield.member[1];
    fdata.data[6] = myfield.efield.member[2];

    fdata.data[7] = myfield.bfield.member[0];
    fdata.data[8] = myfield.bfield.member[1];
    fdata.data[9] = myfield.bfield.member[2];
}
template <typename __Ty>
void clear_vec(vector<__Ty>& vector_to_be_cleaned)
{
    std::vector<__Ty>().swap(vector_to_be_cleaned);
}



struct Particles{
    string name;
    int species;
    double mass;
    double charge;
    double energy;
    __Vect2<double> position;
    __Vect3<double> velocity;
};




#endif
